﻿#include "uring_tcp_server.h"

CallbackParser parsercallback_uring = NULL;

int Init_server(int port)
{
    int listenfd = socket(AF_INET, SOCK_STREAM, 0);

    struct sockaddr_in sockserver;
    memset(&sockserver, 0, sizeof(sockserver));

    sockserver.sin_family = AF_INET;
    sockserver.sin_addr.s_addr = INADDR_ANY;
    sockserver.sin_port = htons(port);
    bind(listenfd, (struct sockaddr *)&sockserver, sizeof(struct sockaddr_in));

    listen(listenfd, 10);

#ifdef PRINTFCMODE
    printf("listenfd:%d\n", listenfd);
#endif
    return listenfd;
}

void set_accept_event(struct io_uring *uring, int fd, struct sockaddr_in *clientaddr, socklen_t *len)
{
    struct io_uring_sqe *sqe = io_uring_get_sqe(uring);

    struct CONN_INFO accept_info = {
        .fd = fd,
        .event = EVENT_ACCEPT,
    };
    io_uring_prep_accept(sqe, fd, (struct sockaddr *)clientaddr, len, 0);
    memcpy(&sqe->user_data, &accept_info, sizeof(struct CONN_INFO));
}

void set_event_recv(struct io_uring *uring, int sockfd, void *buf, size_t len, int flags)
{
    struct io_uring_sqe *sqe = io_uring_get_sqe(uring);
    struct CONN_INFO read_info = {
        .fd = sockfd,
        .event = EVENT_READ,
    };
    io_uring_prep_recv(sqe, sockfd, buf, len, flags);
    memcpy(&sqe->user_data, &read_info, sizeof(struct CONN_INFO));
}

void set_event_send(struct io_uring *uring, int sockfd, void *buf, size_t len, int flags)
{
    struct io_uring_sqe *sqe = io_uring_get_sqe(uring);
    struct CONN_INFO send_info = {
        .fd = sockfd,
        .event = EVENT_WRITE,
    };
    io_uring_prep_send(sqe, sockfd, buf, len, flags);
    memcpy(&sqe->user_data, &send_info, sizeof(struct CONN_INFO));
}

void SetCallbackFun_Uring(int (*CallbackParser)(char *Recvbuff, char *Sendbuff))
{
    parsercallback_uring = CallbackParser;
}

void *runLoop_uring(void *arg)
{
    int sockfd = Init_server(32767);

    struct io_uring_params params;
    memset(&params, 0, sizeof(params));

    struct io_uring uring;
    io_uring_queue_init_params(ENTRES_LENGTH, &uring, &params);

    struct sockaddr_in clientaddr;
    socklen_t len = sizeof(clientaddr);
    set_accept_event(&uring, sockfd, &clientaddr, &len);

    char buffer[BUFFER_LENGTH] = {0};
    char sbuffer[BUFFER_LENGTH] = {0};
    while (1)
    {
        io_uring_submit(&uring);

        struct io_uring_cqe *cqe;
        io_uring_wait_cqe(&uring, &cqe);

        struct io_uring_cqe *cqes[128];
        int nready = io_uring_peek_batch_cqe(&uring, cqes, 128);

        for (int i = 0; i < nready; i++)
        {
            struct io_uring_cqe *cqee = cqes[i];
            struct CONN_INFO info;
            memcpy(&info, &cqee->user_data, sizeof(struct CONN_INFO));

            if (info.event == EVENT_ACCEPT)
            {
                // printf("io_uring_peek_batch_cqe EVENT_ACCEPT\n");
                int clientfd = cqee->res;
                set_accept_event(&uring, sockfd, &clientaddr, &len);
                set_event_recv(&uring, clientfd, buffer, BUFFER_LENGTH, 0);
            }
            else if (info.event == EVENT_READ)
            {
                int ret = cqee->res; // 当是read时，返回可读字节数
                // printf("RECV-%d:%s\n",ret,buffer);
                if (ret == 0)
                {
                    close(info.fd); // 解决断开时一直打印问题
                }
                else if (ret > 0)
                {
                    if (parsercallback_uring != NULL)
                    {
                        parsercallback_uring(buffer, sbuffer);
                    }
                    // printf("set_event_send:%s---len:%d\n",sbuffer,strlen(sbuffer));
                    set_event_send(&uring, info.fd, sbuffer, strlen(sbuffer), 0);
                    memset(buffer,0,BUFFER_LENGTH);
                    set_event_recv(&uring, info.fd, buffer, BUFFER_LENGTH, 0);
                    
                }
            }
            else if (info.event == EVENT_WRITE)
            {
                int ret = cqee->res;
                // printf("SEND-%d:%s\n",ret,buffer);
            }
            
        }

        // 标记事件已处理（必须调用！）
        // io_uring_cqe_seen(&uring, cqe);
        io_uring_cq_advance(&uring, nready); // 批量标记已处理
    }
}

void NetworkStart_Uring(pthread_t *tid)
{
    pthread_create(tid, NULL, runLoop_uring, NULL);
}
